<template>
  <div v-loading="loading" class="formBody">
    <div class="content">
      <div v-for="item in tableList" :key="item.Id">
        <userTable
          v-if="item.TableType == 0"
          :ref="item.Id"
          :key="item.Id"
          :link-biz-pk="linkPk"
          :table="item"
          :readonly="readonly"
          :def-state="defState"
          :power="power"
          :data-source="dataSource"
          :watch-col="watchCol[item.Id]"
          @change="controlChange"
        />
        <userQueryTable
          v-else
          :ref="item.Id"
          :link-biz-pk="linkPk"
          :table="item"
          :power="power"
          :def-state="defState"
          :is-show-btn="isShowBtn"
          :readonly="readonly"
          :data-source="dataSource"
          :watch-col="watchCol[item.Id]"
          @change="controlChange"
          @rowChange="rowChange"
        />
      </div>
    </div>
    <div v-if="readonly == false && isShowBtn && isShowSaveBtn" style="text-align: center">
      <el-button type="primary" @click="save">保存</el-button>
      <el-button @click="initForm">重置</el-button>
    </div>
  </div>
</template>

<script>
import { Get, Calculate, CalculateState } from '@/customForm/api/userForm'
import userTable from './userTable.vue'
import { Set } from '@/customForm/api/userRecord'
import userQueryTable from './userQueryTable.vue'
export default {
  components: {
    userTable,
    userQueryTable
  },
  props: {
    formId: {
      type: String,
      default: null
    },
    linkType: {
      type: String,
      default: null
    },
    linkPk: {
      type: String,
      default: null
    },
    extend: {
      type: Object,
      default: null
    },
    readonly: {
      type: Boolean,
      default: false
    },
    isShowBtn: {
      type: Boolean,
      default: true
    },
    isShowSaveBtn: {
      type: Boolean,
      default: true
    },
    isLoad: {
      type: Boolean,
      default: false
    },
    power: {
      type: Object,
      default: null
    },
    formVal: {
      type: Object,
      default: null
    }
  },
  data() {
    return {
      tableList: [],
      dataSource: {},
      recordId: null,
      watchCol: {},
      initColId: [],
      loading: false,
      defState: null
    }
  },
  computed: {},
  watch: {
    isLoad: {
      handler(val) {
        if (val) {
          this.initForm()
        }
      },
      immediate: true
    }
  },
  mounted() {
  },
  methods: {
    rowChange(e) {
      const list = e.colId.map(c => this.watchCol[e.tableId][c])
      this.refresh(list)
    },
    initArg(list, param) {
      list.forEach(c => {
        param.ColId.push(c.ColId)
        if (c.TableType === 1 && c.TableId in param.RowId === false) {
          param.RowId[c.TableId] = this.dataSource[c.TableId].map(e => e.rowId)
        }
        if (c.WatchCol != null) {
          c.WatchCol.forEach(a => {
            let record = param.Record.find(c => c.TableId === a.TableId)
            if (record == null) {
              record = {
                TableId: a.TableId
              }
              if (a.TableType === 0) {
                record.Rows = [{
                  RowId: 1,
                  Column: {}
                }]
              } else {
                record.Rows = this.dataSource[a.TableId].map(e => {
                  return {
                    RowId: e.rowId,
                    Column: {}
                  }
                })
              }
              param.Record.push(record)
            }
            const row = this.dataSource[a.TableId]
            if (a.TableType === 0) {
              const v = row[a.Name]
              record.Rows[0].Column[a.Name] = v === '' ? null : v
            } else if (a.Name in record.Rows[0].Column === false) {
              for (let i = 0; i < row.length; i++) {
                const v = row[i][a.Name]
                record.Rows[i].Column[a.Name] = v === '' ? null : v
              }
            }
          })
        }
      })
    },
    refresh(list) {
      const param = {
        ColId: [],
        Record: [],
        RowId: {}
      }
      list.forEach(c => {
        this.initArg(c, param)
      })
      this.calculate(param)
    },
    controlChange(e) {
      this.loading = true
      const list = this.watchCol[e.tableId][e.colId]
      const t = list.filter(c => c.type === 0)
      if (t.length !== 0) {
        const param = {
          ColId: [],
          Record: [],
          RowId: {}
        }
        this.initArg(t, param)
        this.calculate(param)
      }
      if (t.length !== list.length) {
        const k = list.filter(c => c.type === 1)
        const param = {
          ColId: [],
          Record: [],
          RowId: {}
        }
        this.initArg(k, param)
        this.syncState(param)
      }
    },
    syncState(param) {
      CalculateState(this.formId, param).then(res => {
        if (res == null || res.length === 0) {
          this.loading = false
          return
        }
        res.forEach(a => {
          this.setColumnState(a)
        })
        this.loading = false
      }).catch((e) => {
        this.loading = false
      })
    },
    calculate(param) {
      Calculate(this.formId, param).then(res => {
        if (res == null || res.length === 0) {
          this.loading = false
          return
        }
        const list = []
        const tc = {}
        res.forEach(a => {
          this.setColumn(a)
          if (a.ColId in tc === false) {
            tc[a.colId] = true
            const t = this.watchCol[a.TableId][a.ColId]
            if (t != null) {
              list.push(t)
            }
          }
        })
        if (list.length > 0) {
          this.refresh(list)
          return
        }
        this.loading = false
      }).catch((e) => {
        this.loading = false
      })
    },
    setColumnState(e) {
      if (e.TableType === 0) {
        this.defState[e.ColId] = e.State
        // Vue.set(row, e.Name, e.Val)
      } else {
        const row = this.dataSource[e.TableId]
        const r = row.find(c => c.rowId === e.RowId)
        if (r.ColState == null) {
          r.ColState = {}
        }
        r.ColState[e.ColId] = e.State
        this.$refs[e.TableId][0].refresh()
      }
    },
    setColumn(e) {
      const row = this.dataSource[e.TableId]
      if (e.TableType === 0) {
        row[e.Name] = e.Val
        // Vue.set(row, e.Name, e.Val)
      } else {
        const r = row.find(c => c.rowId === e.RowId)
        r[e.Name] = e.Val
      }
    },
    async save() {
      for (let i = 0; i < this.tableList.length; i++) {
        const table = this.tableList[i]
        const control = this.$refs[table.Id][0]
        const res = await control.validate()
        if (res === false) {
          return false
        }
      }
      const data = this.getRecordData()
      this.recordId = await Set(data)
      this.$message({
        type: 'success',
        message: '保存成功!'
      })
      this.$emit('save')
    },
    getRecordData() {
      return {
        FormId: this.formId,
        LinkType: this.linkType,
        LinkPK: this.linkPk,
        Table: this.tableList.map(c => {
          const table = {
            TableId: c.Id
          }
          const data = this.dataSource[c.Id]
          if (c.TableType === 0 && data != null) {
            const row = {
              RowId: 1,
              Column: data
            }
            table.Rows = [row]
          } else if (c.TableType === 1 && data != null && data.length > 0) {
            table.Rows = data.map(r => {
              const row = Object.assign({}, r)
              delete row.rowId
              delete row.defState
              return {
                RowId: r.rowId,
                Column: row
              }
            })
          }
          return table
        })
      }
    },
    async initForm() {
      const res = await Get({
        FormId: this.formId,
        LinkType: this.linkType,
        LinkPk: this.linkPk,
        Extend: this.extend,
        FillValue: this.formVal
      })
      this.recordId = res.RecordId
      this.defState = res.DefState
      this.watchCol = {}
      if (res.UserFormula && res.UserFormula.length > 0) {
        this.loadFormula(res.UserFormula, 0)
      }
      if (res.StateFormula && res.StateFormula.length > 0) {
        this.loadFormula(res.StateFormula, 1)
      }
      if (res.Table != null) {
        res.Table.forEach(a => {
          if (a.TableType === 0) {
            if (a.Row == null) {
              this.dataSource[a.Id] = {}
            } else {
              this.dataSource[a.Id] = a.Row.Values
            }
          } else if (a.Rows == null || a.Rows.length === 0) {
            this.dataSource[a.Id] = []
          } else {
            this.dataSource[a.Id] = a.Rows.map(c => {
              const row = c.Values
              row.rowId = c.RowId
              row.ColState = c.ColState
              return row
            })
          }
        })
        this.tableList = res.Table
      } else {
        this.tableList = []
      }
      this.$emit('load', res)
    },
    loadFormula(formulas, type) {
      formulas.forEach(c => {
        c.type = type
        if (c.WatchCol && c.WatchCol.length > 0) {
          c.WatchCol.forEach(a => {
            let data = this.watchCol[a.TableId]
            if (data == null) {
              data = {}
              data[a.ColId] = [c]
              this.watchCol[a.TableId] = data
            } else if (a.ColId in data) {
              data[a.ColId].push(c)
            } else {
              data[a.ColId] = [c]
            }
          })
        } else if (c.TableId in this.watchCol) {
          if (c.ColId in this.watchCol[c.TableId]) {
            this.watchCol[c.TableId].push(c)
          } else {
            this.watchCol[c.TableId][c.ColId] = [c]
          }
        } else {
          this.watchCol[c.TableId] = {}
          this.watchCol[c.TableId][c.ColId] = [c]
        }
      })
    }
  }
}
</script>
  <style scoped>
.formBody {
  width: 100%;
  min-width: 1290px;
  text-align: center;
}
.formBody .content {
  width: 1280px;
  display: inline-block;
  border: 0;
  padding: 10px;
  text-align: initial;
}
</style>
